/**
 * Copyright (C) 2011 Andrew C. Love (DNC) <dnc.app.sup@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dnc.tools.gen;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.GeneratedXmlFile;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.TopLevelClass;

public class MybatisServiceGeneratorPlugin extends PluginAdapter {
	
    //private static VelocityProcessor velocityProcessor = new VelocityProcessor();
    private Properties velocityProperties = new Properties();
    private VelocityProcessor velocityProcessor = new VelocityProcessor();
    File genSpringBeansFile = null;
    File genServiceInterfaceFile = null;
    File genServiceImplFile = null;
    
    private String authorName;
    private String authorEmail;
    private String servicePackage;
    private String targetProject;
    private String springBeansTemplate;
    private String serviceInterfaceTemplate;
    private String serviceImplTemplate;
    private Date generationDateTime;
    private String generationDateTimeString;
    private File vmServiceInterfaceFile;
    private File vmServiceImplFile;
    
    private List <CloakBeanInfo> cloakBeans = new ArrayList<CloakBeanInfo>(); 
    
    @Override
	public boolean validate(List<String> arg0) {
		return true;
	}
    	
	@Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles() {
        return super.contextGenerateAdditionalJavaFiles();
    }
	
	@Override
    public List<GeneratedXmlFile> contextGenerateAdditionalXmlFiles() {
       try {
           velocityProperties.put("cloakBeanList",cloakBeans);
           genSpringBeansFile = new File(targetProject + "/" +  "SpringBeans.xml"); 
           String springBeansContent = velocityProcessor.processTemplate(springBeansTemplate, velocityProperties);
           writeFileContent(genSpringBeansFile, springBeansContent);
        } 
        catch (IOException e) {
            e.printStackTrace();
            System.err.println(e);
        }        
	    
        return super.contextGenerateAdditionalXmlFiles();
    }
	
    @Override
	public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        
        CloakBeanInfo cloakBeanInfo = new CloakBeanInfo();
        cloakBeans.add(cloakBeanInfo);        
        velocityProperties.put("cloakBean",cloakBeanInfo);
        
        cloakBeanInfo.setContainsBlobFields(false);
        List<Field> fields = topLevelClass.getFields();
        for (Iterator iterator = fields.iterator(); iterator.hasNext();) {
            Field field = (Field) iterator.next();
            
            if (field.getType().getShortName().contains("byte[]")){
                cloakBeanInfo.setContainsBlobFields(true);
            }
        }
        
        authorName = this.getProperties().getProperty("authorName");
        velocityProperties.put("authorName", authorName);
        cloakBeanInfo.setAuthorName(authorName);

        authorEmail = this.getProperties().getProperty("authorEmail");
        velocityProperties.put("authorEmail", authorEmail);        
        cloakBeanInfo.setAuthorEmail(authorEmail);
        
        servicePackage = this.getProperties().getProperty("servicePackage");
        velocityProperties.put("servicePackage", servicePackage);
        cloakBeanInfo.setServicePackage(servicePackage);
        
        targetProject = this.getProperties().getProperty("targetProject");
        velocityProperties.put("targetProject", targetProject);
        cloakBeanInfo.setTargetProject(targetProject);
        
        springBeansTemplate = this.getProperties().getProperty("springBeansTemplate");
        vmServiceInterfaceFile = new File(springBeansTemplate);
        cloakBeanInfo.setSpringBeansTemplate(springBeansTemplate);

        serviceInterfaceTemplate = this.getProperties().getProperty("serviceInterfaceTemplate");
        vmServiceInterfaceFile = new File(serviceInterfaceTemplate);
        cloakBeanInfo.setServiceInterfaceTemplate(serviceInterfaceTemplate);
        
        serviceImplTemplate = this.getProperties().getProperty("serviceImplTemplate");
        vmServiceImplFile = new File(serviceImplTemplate);
        cloakBeanInfo.setServiceImplTemplate(serviceImplTemplate);
      
        generationDateTime = new Date();        
        SimpleDateFormat dateformatter = new SimpleDateFormat("MM-dd-yyyy HH.mm.ss.SSS z");
        generationDateTimeString = dateformatter.format(generationDateTime);
        velocityProperties.put("generationDateTime", generationDateTimeString);
        cloakBeanInfo.setGenerationDateTime(generationDateTimeString);
  	        
        velocityProperties.put("modelClassName", topLevelClass.getType().getFullyQualifiedName());
        cloakBeanInfo.setModelClassName(topLevelClass.getType().getFullyQualifiedName());
        
        velocityProperties.put("shortModelClassName", topLevelClass.getType().getShortName());
        cloakBeanInfo.setShortModelClassName(topLevelClass.getType().getShortName());
        
        velocityProperties.put("modelClassNameExample", topLevelClass.getType().getFullyQualifiedName() + "Example");
        cloakBeanInfo.setModelClassNameExample(topLevelClass.getType().getFullyQualifiedName() + "Example");
        
        velocityProperties.put("shortModelClassNameExample", topLevelClass.getType().getShortName() + "Example");
        cloakBeanInfo.setShortModelClassNameExample(topLevelClass.getType().getShortName() + "Example");
        
        velocityProperties.put("mapperClassName", topLevelClass.getType().getFullyQualifiedName() + "Mapper");
        cloakBeanInfo.setMapperClassName(topLevelClass.getType().getFullyQualifiedName() + "Mapper");
        
        velocityProperties.put("shortMapperClassName", topLevelClass.getType().getShortName() + "Mapper");
        cloakBeanInfo.setShortMapperClassName(topLevelClass.getType().getShortName() + "Mapper");
        
        velocityProperties.put("introspectedTable", introspectedTable.getFullyQualifiedTableNameAtRuntime());
        cloakBeanInfo.setIntrospectedTable(introspectedTable.getFullyQualifiedTableNameAtRuntime());
                
        String serviceBeanName = topLevelClass.getType().getShortName().substring(0,1).toLowerCase() + topLevelClass.getType().getShortName().substring(1) + "Service";
        velocityProperties.put("serviceBeanName", serviceBeanName);
        cloakBeanInfo.setServiceBeanName(serviceBeanName);
        
        String mapperBeanName = topLevelClass.getType().getShortName().substring(0,1).toLowerCase() + topLevelClass.getType().getShortName().substring(1) + "Mapper";
        velocityProperties.put("mapperBeanName", mapperBeanName);
        cloakBeanInfo.setMapperBeanName(mapperBeanName);
        
        List<IntrospectedColumn> primaryColumns = introspectedTable.getPrimaryKeyColumns();
        
        for (Iterator iterator = primaryColumns.iterator(); iterator.hasNext();) {
            IntrospectedColumn introspectedColumn = (IntrospectedColumn) iterator.next();
            introspectedColumn.getJavaProperty();            
        }
        
        List<String> primaryKeyColumnsList = new ArrayList<String>();        
        cloakBeanInfo.setPrimaryKeyColumnsList(primaryKeyColumnsList);
        List<IntrospectedColumn> introspectedTablePrimaryKeyColumnList = introspectedTable.getPrimaryKeyColumns();
        for (Iterator iterator = introspectedTablePrimaryKeyColumnList.iterator(); iterator.hasNext();) {
            IntrospectedColumn introspectedColumn = (IntrospectedColumn) iterator.next();
            
            String modelPropertyName = introspectedColumn.getJavaProperty();
            modelPropertyName = modelPropertyName.substring(0,1).toUpperCase() + modelPropertyName.substring(1);
            primaryKeyColumnsList.add(modelPropertyName);            
        }
        
        genServiceInterfaceFile = new File(targetProject + "/" +  topLevelClass.getType().getShortName() + "Service.java"); 
        genServiceImplFile = new File(targetProject + "/" +  topLevelClass.getType().getShortName() + "ServiceImpl.java");
		
        String serviceInterfaceContent = velocityProcessor.processTemplate(serviceInterfaceTemplate, velocityProperties);
        String serviceimplContent = velocityProcessor.processTemplate(serviceImplTemplate, velocityProperties);
        
        try {
            writeFileContent(genServiceInterfaceFile, serviceInterfaceContent);
            writeFileContent(genServiceImplFile, serviceimplContent);
        } 
        catch (IOException e) {
            e.printStackTrace();
            System.err.println(e);
        }        
        
		return super.modelBaseRecordClassGenerated(topLevelClass, introspectedTable);
	}

	@Override
	public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
	    if (topLevelClass!=null){
	    }
	    return super.clientGenerated(interfaze, topLevelClass, introspectedTable);
	}
	
    @Override
    public boolean providerGenerated(TopLevelClass topLevelClass,IntrospectedTable introspectedTable) {
        if (topLevelClass!=null){
        }
        return super.providerGenerated(topLevelClass, introspectedTable);
    }
    
    @Override
    public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {
        return super.sqlMapGenerated(sqlMap, introspectedTable);
    }

    private void writeFileContent(File file, String content) throws IOException {
        //use buffering
        Writer output = new BufferedWriter(new FileWriter(file));
        try {
          output.write( content );
        }
        finally {
          output.close();
        }
    }
	
}
